#include "Map.h"

// Utility function declarations
bool ConvertToInt( char *c , int &f );

Map::~Map(void)
{
	Erase();
}

void Map::Erase()
{
	if (mMap)
	{
		for (int i = 0; i < mHeight; ++i)
		{
			delete [] mMap[i];
		}
		delete [] mMap;
		mMap = 0;
	}
}


// Loads a map file
bool Map::LoadFile(char* filename)
{
	std::ifstream myFile;

	myFile.open(filename);

	if (!myFile.good())
		return false;

	char buffer[MAX_LINE];

	myFile.getline(buffer, MAX_LINE);

	bool heightFound = false;

	// parse the line using a delimiter
	ConvertToInt(strtok(buffer, " "), mWidth);
	ConvertToInt(strtok(0, " "), mHeight);

	// create the dynamically allocated array
	mMap = new char*[mHeight];
	for(int i = 0; i < mHeight; ++i)
	{
		mMap[i] = new char[mWidth];
	}

	// read the rest of the file
	int lineNum = 0;

	while(!myFile.eof())
	{
		myFile.getline(buffer, MAX_LINE); // gets a character from the file

		for(int i = 0; i < strlen(buffer); ++i)
		{
			mMap[lineNum][i] = buffer[i];
		}
		++lineNum;
	}
	return true;
}

void Map::DrawElement(char c)
{
	if (c != ' ')
		printf("%c", c);
}

// draws the map to the screen
void Map::Draw(void)
{
	for(int i = 0; i < mHeight; i++)
	{
		for(int j = 0; j < mWidth; j++)
		{
			DrawElement(mMap[i][j]);
		}
		printf("\n");
	}
}

// draws the map to a specific coordinate on the screen
// x/y denotes the top-left coord
void Map::Draw(int x, int y)
{
	for(int i = 0; i < mHeight; i++)
	{
		for(int j = 0; j < mWidth; j++)
		{
			COORD point = {x+j, y+i};
			SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), point);
			DrawElement(mMap[i][j]);
		}
		printf("\n");
	}
}

void Map::DrawFlippedH(int x, int y)
{
	// Draws the map reverse-horizontally
	for(int i = 0; i < mHeight; i++)
	{
		for(int j = 0; j < mWidth; j++)
		{
			COORD point = {x+j, y+i};
			SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), point);
			DrawElement(mMap[i][(mWidth-1)-j]);
		}
		printf("\n");
	}
}

void Map::DrawFlippedV(int x, int y)
{
	// Draws the map reverse-vertically
	for(int i = 0; i < mHeight; i++)
	{
		for(int j = 0; j < mWidth; j++)
		{
			COORD point = {x+j, y+i};
			SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), point);
			DrawElement(mMap[(mHeight-1)-i][j]);
		}
		printf("\n");
	}
}

void Map::DrawFlippedXY(int x, int y)
{
	// Draws the map flipped diagonally
	for(int i = 0; i < mWidth; i++)
	{
		for(int j = 0; j < mHeight; j++)
		{
			COORD point = {x+j, y+i};
			SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), point);
			DrawElement(mMap[j][i]);
		}
		printf("\n");
	}
}

void Map::DrawRotatedCW(int x, int y)
{
	for(int i = 0; i < mWidth; i++)
	{
		for(int j = 0; j < mHeight; j++)
		{
			COORD point = {x+j, y+i};
			SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), point);
			DrawElement(mMap[(mHeight-1)-j][i]);
		}
		printf("\n");
	}
}

void Map::DrawRotatedCCW(int x, int y)
{
	for(int i = 0; i < mWidth; i++)
	{
		for(int j = 0; j < mHeight; j++)
		{
			COORD point = {x+j, y+i};
			SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), point);
			DrawElement(mMap[j][(mWidth-1)-i]);
		}
		printf("\n");
	}
}

void Map::FlipH()
{
	// create a new array of the proper size
	char ** newData = new char*[mHeight];
	for(int i = 0; i < mHeight; ++i)
	{
		newData[i] = new char[mWidth];
	}

	// Draws the map reverse-horizontally
	for(int i = 0; i < mHeight; i++)
	{
		for(int j = 0; j < mWidth; j++)
		{
			newData[i][j] = mMap[i][(mWidth-1)-j];
		}
	}

	// delete old data
	for(int i = 0; i < mHeight; ++i)
	{
		delete [] mMap[i];
	}
	delete [] mMap;

	// set the new pointer-pointer
	mMap = newData;

	// width and height stay the same, no need to change them.
}

void Map::FlipV()
{
	// create a new array of the proper size
	char ** newData = new char*[mHeight];
	for(int i = 0; i < mHeight; ++i)
	{
		newData[i] = new char[mWidth];
	}

	// Draws the map reverse-horizontally
	for(int i = 0; i < mHeight; i++)
	{
		for(int j = 0; j < mWidth; j++)
		{
			newData[i][j] = mMap[(mHeight-1)-i][j];
		}
	}

	// delete old data
	for(int i = 0; i < mHeight; ++i)
	{
		delete [] mMap[i];
	}
	delete [] mMap;

	// set the new pointer-pointer
	mMap = newData;

	// width and height stay the same, no need to change them.
}

void Map::FlipXY()
{
	// create a new array of the proper size
	char ** newData = new char*[mWidth];
	for(int i = 0; i < mWidth; ++i)
	{
		newData[i] = new char[mHeight];
	}

	// Draws the map reverse-horizontally
	for(int i = 0; i < mWidth; i++)
	{
		for(int j = 0; j < mHeight; j++)
		{
			newData[i][j] = mMap[j][i];
		}
	}

	// delete old data
	for(int i = 0; i < mHeight; ++i)
	{
		delete [] mMap[i];
	}
	delete [] mMap;

	// set the new pointer-pointer
	mMap = newData;

	// width and height flip around
	int temp = mWidth;
	mWidth = mHeight;
	mHeight = temp;
}

void Map::RotateCW()
{
	// create a new array of the proper size
	char ** newData = new char*[mWidth];
	for(int i = 0; i < mWidth; ++i)
	{
		newData[i] = new char[mHeight];
	}

	// Draws the map reverse-horizontally
	for(int i = 0; i < mWidth; i++)
	{
		for(int j = 0; j < mHeight; j++)
		{
			newData[i][j] = mMap[(mHeight-1)-j][i];
		}
	}

	// delete old data
	for(int i = 0; i < mHeight; ++i)
	{
		delete [] mMap[i];
	}
	delete [] mMap;

	// set the new pointer-pointer
	mMap = newData;

	// width and height flip around
	int temp = mWidth;
	mWidth = mHeight;
	mHeight = temp;
}

void Map::RotateCCW()
{
	// create a new array of the proper size
	char ** newData = new char*[mWidth];
	for(int i = 0; i < mWidth; ++i)
	{
		newData[i] = new char[mHeight];
	}

	// Draws the map reverse-horizontally
	for(int i = 0; i < mWidth; i++)
	{
		for(int j = 0; j < mHeight; j++)
		{
			newData[i][j] = mMap[j][(mWidth-1)-i];
		}
	}

	// delete old data
	for(int i = 0; i < mHeight; ++i)
	{
		delete [] mMap[i];
	}
	delete [] mMap;

	// set the new pointer-pointer
	mMap = newData;

	// width and height flip around
	int temp = mWidth;
	mWidth = mHeight;
	mHeight = temp;
}

char Map::GetElement(int x, int y)
{
	if (y >= 0 && y <= mHeight)
		if (x >= 0 && x <= mWidth)
			return mMap[y][x];
		else
			return 0;
	else
		return 0;
}

void Map::SetElement(int x, int y, char c)
{
	if (y >= 0 && y <= mHeight)
		if (x >= 0 && x <= mWidth)
			mMap[y][x] = c;	
}

void Map::Copy(Map &target)
{
	// if I have data, erase it
	Erase();

	// create a new array the same size as the target
	mHeight = target.mHeight;
	mWidth = target.mWidth;

	mMap = new char*[mHeight];
	for(int i = 0; i < mHeight; ++i)
	{
		mMap[i] = new char[mWidth];
	}

	// copy data
	for (int i = 0; i < mHeight; ++i)
	{
		for (int j = 0; j < mWidth; j++)
		{
			mMap[i][j] = target.mMap[i][j];
		}
	}
}

////////////////////////////////////////////////
// ConvertToInt()
//
// A helper function to turn a char* which
// is known to represent an int, into a usable
// int value
////////////////////////////////////////////////
bool ConvertToInt( char *c , int &i )
{ 
	i = 0 ;
	
	if ( *c == '\0' ) 
		return false ;

	while ( *c != '\0' && *c != '.' )
	{ 
		if ( *c < '0' || *c > '9' ) 
			return false ;

		i = i * 10 + *c++ - '0' ;
	}

	return true ;
}